package xyz.xtt.pay.support;

import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.client.response.AssetAllInfoResponse;
import xyz.xtt.asset.client.response.AssetInfoResponse;
import xyz.xtt.asset.client.response.TransactionResponse;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.dto.PayCenterOrderStatusResponse;
import xyz.xtt.pay.entity.TblPayOrder;
import xyz.xtt.pay.utils.AESUtil;
import xyz.xtt.pay.vo.PayCenterArgsResponse;
import xyz.xtt.pay.vo.PayCenterPayParam;
import xyz.xtt.pay.vo.paycenter.SendRefundRequest;
import xyz.xtt.user.client.response.UserInfoResponse;

/**
 * 支付中心相关http接口服务
 *
 * @author dale
 * @since 2024/12/30
 **/
@RefreshScope
@Slf4j
@Component
public class PayCenterHttpService {
	private static final String NFT_ORDER_PREFIX = "NFT_";
	private static final String PAY_CENTER_API_PROTOCOL = "https://";
	private static final String ORDER_REFUND_APPLY_PATH = "/nx2cloud/nx2cloud-app-pay/payOrderApi/payOrderRefund";
	private static final String PAY_ORDER_QUERY_PATH = "/nx2cloud/nx2cloud-app-pay/payOrderApi/payOrderQuery";

	@Value("${pay.center.app.id}")
	private String appId;

	@Value("${pay.center.app.secret}")
	private String appSecret;

	@Value("${pay.center.api.host}")
	private String payCenterHost;

	@Value("${pay.center.modes}")
	private List<Integer> payModeList;

	@Value("${pay.center.page.url}")
	private String payCenterPageUrl;

	/**
	 * 发送退款请求
	 *
	 * @param transaction 交易记录
	 * @param payMode     支付渠道
	 * @param payModeSub  支付子渠道
	 * @return 结果
	 */
	public boolean sendRefundRequest(TransactionResponse transaction, int payMode, int payModeSub) {
		BigDecimal totalPrice = transaction.getAmount().multiply(transaction.getPrice());
		SendRefundRequest refundParam = SendRefundRequest
				.builder()
				.orderNo(NFT_ORDER_PREFIX + transaction.getOrderId())
				.tradeNo(NFT_ORDER_PREFIX + transaction.getOrderId())
				.refundTradeNo(NFT_ORDER_PREFIX + transaction.getOrderId() + "-1")
				.amount(totalPrice.doubleValue())
				.userId(transaction.getBuyerUserId())
				.payMode(payMode)
				.payModeSub(payModeSub)
				.refundReason("订单退款")
				.build();
		refundParam.setAmountTotal(refundParam.getAmount());
		refundParam.setAmountRefundTotal(refundParam.getAmount());
		refundParam.setOccurOuCode(appId);
		log.info("sendRefundRequest param: {}", JSONUtil.toJsonStr(refundParam));

		URI uri = URI.create(PAY_CENTER_API_PROTOCOL + payCenterHost + ORDER_REFUND_APPLY_PATH);
		HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).connectTimeout(Duration.ofSeconds(10)).build();
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(uri)
				.header("appId", appId)
				.header("sign", generateSign(refundParam.getOrderNo(), totalPrice))
				.header("Content-Type", "application/json")
				.timeout(Duration.ofSeconds(10))
				.POST(HttpRequest.BodyPublishers.ofString(JSONUtil.toJsonStr(refundParam)))
				.build();
		try {
			String body = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
			log.info("sendRefundRequest response: {}", body);
			return Objects.equals(JSONUtil.parseObj(body).getInt("code"), 0)
					&& Objects.equals(JSONUtil.parseObj(body).getJSONObject("data").getInt("state"), 0);
		} catch (Exception e) {
			log.error("sendRefundRequest error", e);
		}
		return false;
	}

	/**
	 * 计算签名
	 * 
	 * @param orderNo
	 * @param amount
	 * @return
	 */
	public String generateSign(String orderNo, BigDecimal amount) {
		String beforeSignStr = orderNo + amount.stripTrailingZeros().toPlainString() + appId + appSecret;
		log.info("beforeSignStr:{}", beforeSignStr);
		return MD5.create().digestHex(beforeSignStr, CharsetUtil.UTF_8).toUpperCase();
	}

	public PayCenterArgsResponse buildCreateOrderParams(TblPayOrder payOrder, UserInfoResponse user, String backUrl, AssetAllInfoResponse assetExpandDto) {
//        TblAsset asset = new TblAsset();
		AssetInfoResponse asset = new AssetInfoResponse();
		BeanUtils.copyProperties(assetExpandDto.getAsset(), asset);
		return buildCreateOrderParams(payOrder, user, backUrl, asset);
	}

	public PayCenterArgsResponse buildCreateOrderParams(TblPayOrder payOrder, UserInfoResponse user, String backUrl, AssetInfoResponse asset) {
		String phone = user.getPhone();
		if (StringUtils.isNotBlank(phone)) {
			try {
				phone = AESUtil.decrypt(phone);
			} catch (Exception e) {
				log.error("decrypt phone error. phone:{} error:{}", phone, e);
			}
			if (phone.startsWith("86")) {
				phone = phone.substring(2);
			}
		}

		PayCenterPayParam param = PayCenterPayParam
				.builder()
				.userId(user.getAppUserId() + "")
				.mobile(phone)
				.orderType(NFT_ORDER_PREFIX + PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType()).name())
				.tradeNo(NFT_ORDER_PREFIX + payOrder.getPayOrderId())
				.amount(payOrder.getPayMoney().doubleValue())
				.payMode(payModeList)
				.body(PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType()).name())
				.appId(appId)
				.backUrl(backUrl)
				.build();
		param.setExternalCode(param.getUserId());
		param.setOrderNo(param.getTradeNo());
		param.setAmountTotal(param.getAmount());
		param.setOccurOuCode(param.getAppId());
		param.setSign(generateSign(param.getOrderNo(), payOrder.getPayMoney()));
		if (asset != null) {
			param.setGoodsId(asset.getGoodsId());
		}
		param.setIsPaymentResults("true");
		PayCenterArgsResponse response = PayCenterArgsResponse.builder().payCenterUrl(payCenterPageUrl).payParam(param).createNewOrder(true).build();
		return response;
	}

	/**
	 * 查询支付中心订单状态
	 *
	 * @param orderId   订单号
	 * @param appUserId 用户id
	 * @param amount    订单金额
	 * @return 订单状态
	 */
	public PayCenterOrderStatusResponse queryPayOrderStatus(@Positive long orderId, @NotNull String appUserId, @NotNull BigDecimal amount) {
		URI uri = URI.create(PAY_CENTER_API_PROTOCOL + payCenterHost + PAY_ORDER_QUERY_PATH);
		String orderNo = NFT_ORDER_PREFIX + orderId;
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("tradeNo", orderNo);
		paramMap.put("orderNo", orderNo);
		paramMap.put("userId", appUserId);

		HttpClient client = HttpClient
				.newBuilder()
				.followRedirects(HttpClient.Redirect.NORMAL)
				.connectTimeout(Duration.ofSeconds(10))
				.version(HttpClient.Version.HTTP_1_1)
				.build();
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(uri)
				.header("appId", appId)
				.header("sign", generateSign(orderNo, amount))
				.header("Content-Type", "application/json")
				.timeout(Duration.ofSeconds(10))
				.POST(HttpRequest.BodyPublishers.ofString(JSONUtil.toJsonStr(paramMap)))
				.build();
		try {
			log.info("queryPayOrderStatus orderNo:{}", orderNo);
			String body = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
			log.info("queryPayOrderStatus response: {}", body);
			if (!JSONUtil.isTypeJSON(body)) {
				log.error("queryPayOrderStatus response data is not valid");
				return null;
			}
			JSONObject jsonObject = JSONUtil.parseObj(body);
			if (!Objects.equals(jsonObject.getInt("code"), 0)) {
				log.error("queryPayOrderStatus response error");
				return null;
			}
			return jsonObject.get("data", PayCenterOrderStatusResponse.class);
		} catch (Exception e) {
			log.error("queryPayOrderStatus exception", e);
		}
		return null;
	}
}
